// Copyright (c) 2005  INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of cgal-python; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; version 2.1 of the License.
// See the file LICENSE.LGPL distributed with cgal-python.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $Id: Py_Triangulation_2.cpp 167 2007-11-02 15:36:54Z spion $
// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal-python/trunk/cgal-python/bindings/Triangulations_2/Py_Triangulation_2.cpp $
//
// Author(s)     : Naceur Meskini
//=========================================================================

#include <CGAL/basic.h>
#include <include/Kernels.h>
#include <include/iterator.h>

#include <CGAL/Triangulation_2.h>

#include <CGAL/Alpha_shape_vertex_base_2.h>
#include <CGAL/Triangulation_hierarchy_vertex_base_2.h>
#include <CGAL/Triangulation_vertex_base_with_info_2.h>

#include <CGAL/Alpha_shape_face_base_2.h>
#include <CGAL/Delaunay_mesh_face_base_2.h>


#include <CGAL/circulator.h>
#include "Py_Triangulation_2_doc.h"

#include <boost/python.hpp>
#include <boost/cstdint.hpp>
#include <list>
#include <iostream>


using namespace boost::python;

namespace {
	BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(is_valid_overloads_0_2, is_valid, 0, 2)
	BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(insert_overloads_1_2, insert, 1, 2)
	BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(remove_degree_3_overloads_1_2, remove_degree_3, 1, 2)	
	BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(locate_overloads_3_4, locate, 3, 4)	
	BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(locate_overloads_1_2, locate, 1, 2)	
}

template < class iterator,class Triangulation>
simple_python_iterator<iterator> py_points(Triangulation& dt)
{
	std::pair< iterator , iterator > p( dt.points_begin(), dt.points_end() );
	return simple_python_iterator<iterator>(p);
}
template < class iterator,class Handle,class Triangulation>
Handle_to_py_iterator<iterator,Handle> py_vertices(Triangulation& dt)
{
	std::pair< iterator , iterator > p( dt.finite_vertices_begin(), dt.finite_vertices_end() );
	return Handle_to_py_iterator<iterator,Handle>(p);
}
template < class iterator,class Handle,class Triangulation>
Handle_to_py_iterator<iterator,Handle> py_all_vertices(Triangulation& dt)
{
	std::pair< iterator , iterator > p( dt.all_vertices_begin(), dt.all_vertices_end() );
	return Handle_to_py_iterator<iterator,Handle>(p);
}
template < class iterator,class Handle,class Triangulation>
Handle_to_py_iterator<iterator,Handle> py_faces(Triangulation& dt)
{
	std::pair< iterator , iterator > p( dt.finite_faces_begin(), dt.finite_faces_end() );
	return Handle_to_py_iterator<iterator,Handle>(p);
}
template < class iterator,class Handle,class Triangulation>
Handle_to_py_iterator<iterator,Handle> py_all_faces(Triangulation& dt)
{
	std::pair< iterator , iterator > p( dt.all_faces_begin(), dt.all_faces_end() );
	return Handle_to_py_iterator<iterator,Handle>(p);
}
template < class iterator,class Triangulation>
simple_python_iterator<iterator> py_edges(Triangulation& dt)
{
	std::pair< iterator , iterator > p( dt.finite_edges_begin(), dt.finite_edges_end() );
	return simple_python_iterator<iterator>(p);
}
template < class iterator,class Triangulation>
simple_python_iterator<iterator> py_all_edges(Triangulation& dt)
{
	std::pair< iterator , iterator > p( dt.all_edges_begin(), dt.all_edges_end() );
	return simple_python_iterator<iterator>(p);
}
template < class kernel,class Triangulation>
void py_insert(Triangulation& dt,boost::python::list pts)
{
	typedef typename kernel::Point_2 Point_2;
	for(int i = 0 ; i < pts.attr("__len__")() ; i++)
	{
		Point_2 P = boost::python::extract<Point_2>(pts[i]); 
		dt.insert(P);
	}
}
template < class Triangulation,class Face_handle,class Point_2>
Face_handle py_locate(Triangulation& tri,Point_2 pt,boost::python::list& liste/*,Face_handle fh = Face_handle()*/)
{
	Face_handle result;
	typedef typename Triangulation::Locate_type Locate_type;
	Locate_type lt;
	int ti;
	int N = boost::python::extract<int>(liste.attr("__len__")());
	if (N >= 1) for(int i = 0 ; i < N ; i++) liste.remove(liste[0]);
	result = tri.locate(pt,lt,ti);
	liste.append(lt);
	liste.append(ti);
	return result;
}
//Face, Edge and Vertex Circulators=====================
template < class circulator,class Vertex_handle,class Face_handle,class Triangulation>
circulator_to_py_iterator<circulator,Face_handle> py_incident_faces(Triangulation& dt,Vertex_handle v)
{
	circulator first = dt.incident_faces(v),last;
	std::pair< circulator , circulator > p( first, last);
	return circulator_to_py_iterator<circulator,Face_handle>(p);
}
template < class circulator,class Vertex_handle,class Face_handle,class Triangulation>
circulator_to_py_iterator<circulator,Face_handle> py_incident_faces_2(Triangulation& dt,Vertex_handle v,Face_handle f)
{
	circulator first = dt.incident_faces(v,f),last;
	std::pair< circulator , circulator > p( first, last);
	return circulator_to_py_iterator<circulator,Face_handle>(p);
}

template < class circulator,class Vertex_handle,class Triangulation>
simple_python_circulator<circulator> py_incident_edges(Triangulation& dt,Vertex_handle v)
{
	circulator first = dt.incident_edges(v),last;
	std::pair< circulator , circulator > p( first, last);
	return simple_python_circulator<circulator>(p);

}
template < class circulator,class Vertex_handle,class Face_handle,class Triangulation>
simple_python_circulator<circulator> py_incident_edges_2(Triangulation& dt,Vertex_handle v,Face_handle f)
{
	circulator first = dt.incident_edges(v,f),last;
	std::pair< circulator , circulator > p( first, last);
	return simple_python_circulator<circulator>(p);
}

template < class circulator,class Vertex_handle,class Triangulation>
circulator_to_py_iterator<circulator,Vertex_handle> py_incident_vertices(Triangulation& dt,Vertex_handle v)
{
	circulator first = dt.incident_vertices(v),last;
	std::pair< circulator , circulator > p( first, last);
	return circulator_to_py_iterator<circulator,Vertex_handle>(p);
}

template < class circulator,class Vertex_handle,class Face_handle,class Triangulation>
circulator_to_py_iterator<circulator,Vertex_handle> py_incident_vertices_2(Triangulation& dt,Vertex_handle v,Face_handle f)
{
	circulator first = dt.incident_vertices(v,f),last;
	std::pair< circulator , circulator > p( first, last);
	return circulator_to_py_iterator<circulator,Vertex_handle>(p);
}
template < class circulator,class Point_2,class Triangulation>
boost::python::list py_line_walk(Triangulation& dt,Point_2 p,Point_2 q)
{
	boost::python::list result;
	circulator cir = dt.line_walk(p,q);
	circulator first = cir;
	if (!cir.is_empty())
	{
		do{
			result.append((first++).handle());
		}
		while( first != cir );
	}
	return result;
}


template < class circulator,class Point_2,class Face_handle,class Triangulation>
boost::python::list py_line_walk_2(Triangulation& dt,Point_2 p,Point_2 q,Face_handle f)
{
	boost::python::list result;
	circulator cir = dt.line_walk(p,q,f);
	circulator first = cir;
	if (!cir.is_empty())
	{
		do{
			result.append((first++).handle());
		}
		while( first != cir );
	}
	return result;
}

//END Face, Edge and Vertex Circulators=====================
template < class Triangulation,class Face_handle,class Point_2>
CGAL::Oriented_side oriented_side(const Triangulation& dt,Face_handle f,const Point_2& p)
{
	return dt.oriented_side(f,p);
}

template < class Triangulation,class Vertex_handle>
bool py_is_edge(const Triangulation& tri,Vertex_handle v1,Vertex_handle v2,typename Triangulation::Edge & e)
{
	typedef typename Triangulation::Face_handle Face_handle;
	Face_handle face;
	int i;
	bool result = tri.is_edge(v1,v2,face,i);
	e.first = face;
	e.second = i;
	return result;
}

template < class kernel>
void Py_Triangulation_2()
{
	// three things must be fixed in order to insure the derivation in the python side.
	// -1: the vertex_base 
	// -2: the face_base
	// -3: the data_structure
	typedef CGAL::Alpha_shape_vertex_base_2<kernel> 	Avb;
	typedef CGAL::Triangulation_hierarchy_vertex_base_2<Avb> Hv; //this one is needed when the input data set is huge for the Alpha_shape_2,
																 // say more than 10.000 points,
	typedef CGAL::Triangulation_vertex_base_with_info_2<boost::python::object,kernel,Hv> 	Vb;

	typedef CGAL::Delaunay_mesh_face_base_2<kernel> 	Mf; 
	typedef CGAL::Alpha_shape_face_base_2<kernel,Mf> 	Af;

	typedef CGAL::Triangulation_data_structure_2<Vb,Af> Tds;

	typedef CGAL::Triangulation_2<kernel,Tds>   				Triangulation_2;

	typedef typename Triangulation_2::Finite_faces_iterator 	Finite_faces_iterator;
	typedef typename Triangulation_2::Face_circulator			Face_circulator;
	typedef typename Triangulation_2::All_faces_iterator 	    All_faces_iterator;
	typedef typename Triangulation_2::Face_handle 				Face_handle;

	typedef typename kernel::Point_2 							Point_2;
	typedef typename Triangulation_2::Point_iterator 			Point_iterator;

	typedef typename Triangulation_2::Vertex_handle 			Vertex_handle;
	typedef typename Triangulation_2::Vertex_circulator 		Vertex_circulator;
	typedef typename Triangulation_2::Finite_vertices_iterator 	Finite_vertices_iterator;
	typedef typename Triangulation_2::All_vertices_iterator 	All_vertices_iterator;

	typedef typename Triangulation_2::Edge 						Edge;
	typedef typename Triangulation_2::Finite_edges_iterator		Finite_edges_iterator;
	typedef typename Triangulation_2::Edge_circulator			Edge_circulator;
	typedef typename Triangulation_2::All_edges_iterator		All_edges_iterator;

	typedef typename Triangulation_2::Locate_type 				Locate_type;
	typedef typename kernel::Segment_2 							Segment_2;
	typedef typename Triangulation_2::Line_face_circulator		Line_face_circulator;
	
    scope* In_Triangulation_2 = new scope(
    class_< Triangulation_2 >("Triangulation_2",Triangulation_2_docs[Triangulation_2_doc], init< optional< const kernel& > >())
        .def(init< Triangulation_2& >(Triangulation_2_docs[init_doc]))
	.def("swap", &Triangulation_2::swap,Triangulation_2_docs[swap_doc])
	.def("clear", &Triangulation_2::clear,Triangulation_2_docs[clear_doc])
        .def("dimension", &Triangulation_2::dimension,Triangulation_2_docs[dimension_doc])
        .def("number_of_vertices", &Triangulation_2::number_of_vertices,Triangulation_2_docs[number_of_vertices_doc])
        .def("number_of_faces", &Triangulation_2::number_of_faces,Triangulation_2_docs[number_of_faces_doc])
        .def("infinite_vertex", &Triangulation_2::infinite_vertex,Triangulation_2_docs[infinite_vertex_doc])
        .def("finite_vertex", &Triangulation_2::finite_vertex,Triangulation_2_docs[finite_vertex_doc])
        .def("infinite_face", &Triangulation_2::infinite_face,Triangulation_2_docs[infinite_face_doc])
        .def("infinite_tester", &Triangulation_2::infinite_tester,Triangulation_2_docs[infinite_tester_doc])
        .def("set_infinite_vertex", &Triangulation_2::set_infinite_vertex)
        .def("is_valid", &Triangulation_2::is_valid, is_valid_overloads_0_2(Triangulation_2_docs[is_valid_doc]))
        .def("is_infinite", (bool (Triangulation_2::*)(Face_handle) const)&Triangulation_2::is_infinite,Triangulation_2_docs[is_infinite_doc])
        .def("is_infinite", (bool (Triangulation_2::*)(Vertex_handle) const)&Triangulation_2::is_infinite)
        .def("is_infinite", (bool (Triangulation_2::*)(Face_handle, int) const)&Triangulation_2::is_infinite)
        .def("is_infinite", (bool (Triangulation_2::*)(const Edge&) const)&Triangulation_2::is_infinite)
        .def("is_edge", (bool (Triangulation_2::*)(Vertex_handle, Vertex_handle) const)&Triangulation_2::is_edge,Triangulation_2_docs[is_edge_doc])
        .def("is_edge", &py_is_edge<Triangulation_2,Vertex_handle>)
        .def("includes_edge", &Triangulation_2::includes_edge)
        .def("is_face", (bool (Triangulation_2::*)(Vertex_handle, Vertex_handle, Vertex_handle) const)&Triangulation_2::is_face,Triangulation_2_docs[is_face_doc])
        .def("is_face", (bool (Triangulation_2::*)(Vertex_handle, Vertex_handle, Vertex_handle, Face_handle&) const)&Triangulation_2::is_face)
        .def("triangle", &Triangulation_2::triangle,Triangulation_2_docs[triangle_doc])
        .def("segment", (Segment_2 (Triangulation_2::*)(Face_handle, int) const)&Triangulation_2::segment,Triangulation_2_docs[segment_doc])
        .def("segment", (Segment_2 (Triangulation_2::*)(const Edge&) const)&Triangulation_2::segment)
        .def("segment", (Segment_2 (Triangulation_2::*)(const Finite_edges_iterator&) const)&Triangulation_2::segment)
        .def("circumcenter", (Point_2 (Triangulation_2::*)(Face_handle) const)&Triangulation_2::circumcenter,Triangulation_2_docs[circumcenter_doc])
        .def("circumcenter", (Point_2 (Triangulation_2::*)(const Point_2&, const Point_2&, const Point_2&) const)&Triangulation_2::circumcenter)
        .def("flip", &Triangulation_2::flip,Triangulation_2_docs[flip_doc])
        .def("oriented_side", &oriented_side<Triangulation_2,Face_handle,Point_2>)
        .def("insert_first", &Triangulation_2::insert_first,Triangulation_2_docs[insert_first_doc])
        .def("insert_second", &Triangulation_2::insert_second,Triangulation_2_docs[insert_second_doc])
        .def("insert_in_edge", &Triangulation_2::insert_in_edge,Triangulation_2_docs[insert_in_edge_doc])
        .def("insert_in_face", &Triangulation_2::insert_in_face,Triangulation_2_docs[insert_in_face_doc])
        .def("insert_outside_convex_hull", &Triangulation_2::insert_outside_convex_hull,Triangulation_2_docs[insert_outside_convex_hull_doc])
        .def("insert_outside_affine_hull", &Triangulation_2::insert_outside_affine_hull)
        .def("insert", (Vertex_handle (Triangulation_2::*)(const Point_2&, Face_handle) )&Triangulation_2::insert, insert_overloads_1_2())
        .def("insert", (Vertex_handle (Triangulation_2::*)(const Point_2&, Locate_type, Face_handle, int) )&Triangulation_2::insert)
        .def("insert",&py_insert<kernel,Triangulation_2>,Triangulation_2_docs[insert_doc])
        .def("push_back", &Triangulation_2::push_back,Triangulation_2_docs[push_back_doc])
        .def("remove_degree_3", &Triangulation_2::remove_degree_3, remove_degree_3_overloads_1_2())
        .def("remove_first", &Triangulation_2::remove_first,Triangulation_2_docs[remove_first_doc])
        .def("remove_second", &Triangulation_2::remove_second,Triangulation_2_docs[remove_second_doc])
        .def("remove", &Triangulation_2::remove,Triangulation_2_docs[remove_doc])
	.def("side_of_oriented_circle",&Triangulation_2::side_of_oriented_circle,Triangulation_2_docs[side_of_oriented_circle_doc])
	// add the documentation to this function.
        //.def("locate", (Face_handle (Triangulation_2::*)(const Point_2&, Locate_type&, int&, Face_handle) const)&Triangulation_2::locate,locate_overloads_3_4())
	.def("locate", &py_locate<Triangulation_2,Face_handle,Point_2>/*,arg("Point_2"),arg("list"),arg("Face_handle")=Face_handle()*/)
        .def("locate", (Face_handle (Triangulation_2::*)(const Point_2&, Face_handle) const)&Triangulation_2::locate, locate_overloads_1_2(Triangulation_2_docs[locate_doc]))
      	.def("incident_faces", &py_incident_faces<Face_circulator,Vertex_handle,Face_handle,Triangulation_2>,Triangulation_2_docs[incident_faces_doc])
      	.def("incident_faces",&py_incident_faces_2<Face_circulator,Vertex_handle,Face_handle,Triangulation_2>)
      	.def("incident_edges", &py_incident_edges<Edge_circulator,Vertex_handle,Triangulation_2>,Triangulation_2_docs[incident_edges_doc])
      	.def("incident_edges", &py_incident_edges_2<Edge_circulator,Vertex_handle,Face_handle,Triangulation_2>)
      	.def("incident_vertices", &py_incident_vertices<Vertex_circulator,Vertex_handle,Triangulation_2>,Triangulation_2_docs[incident_vertices_doc])
      	.def("incident_vertices", &py_incident_vertices_2<Vertex_circulator,Vertex_handle,Face_handle,Triangulation_2>)
       	.def("line_walk", &py_line_walk<Line_face_circulator,Point_2,Triangulation_2>,Triangulation_2_docs[line_walk_doc])
       	.def("line_walk", &py_line_walk_2<Line_face_circulator,Point_2,Face_handle,Triangulation_2>)

      	.add_property("faces", &py_faces<Finite_faces_iterator,Face_handle,Triangulation_2>)
	.add_property("vertices", &py_vertices<Finite_vertices_iterator,Vertex_handle,Triangulation_2>)

        .add_property("edges", &py_edges<Finite_edges_iterator,Triangulation_2>)
        .add_property("points", &py_points<Point_iterator,Triangulation_2>)
        .add_property("all_faces", &py_all_faces<All_faces_iterator,Face_handle,Triangulation_2>)
        .add_property("all_vertices", &py_all_vertices<All_vertices_iterator,Vertex_handle,Triangulation_2>)
        .add_property("all_edges", &py_all_edges<All_edges_iterator,Triangulation_2>)
        .def("ccw", &CGAL::Triangulation_cw_ccw_2::ccw,Triangulation_2_docs[ccw_doc])
        .def("cw", &CGAL::Triangulation_cw_ccw_2::cw,Triangulation_2_docs[cw_doc])
        .staticmethod("ccw")
        .staticmethod("cw")
	.def("degree", &Triangulation_2::degree)
        .def("compare_x", &Triangulation_2::compare_x)
        .def("compare_y", &Triangulation_2::compare_y)
        .def("xy_equal", &Triangulation_2::xy_equal)
        .def("mirror_vertex", &Triangulation_2::mirror_vertex)

    );

    enum_< Locate_type >("Locate_type")
        .value("OUTSIDE_CONVEX_HULL", Triangulation_2::OUTSIDE_CONVEX_HULL)
        .value("EDGE", Triangulation_2::EDGE)
        .value("VERTEX", Triangulation_2::VERTEX)
        .value("OUTSIDE_AFFINE_HULL", Triangulation_2::OUTSIDE_AFFINE_HULL)
        .value("FACE", Triangulation_2::FACE)
    ;

    delete In_Triangulation_2;
	simple_python_iterator<Point_iterator>::declare("Point_iterator","iterator over the points corresponding the finite vertices of the triangulation.");
	Handle_to_py_iterator<Finite_vertices_iterator,Vertex_handle>::declare("Vertex_iterator", "iterator over finite vertices.");

	Handle_to_py_iterator<Finite_faces_iterator,Face_handle>::declare("Face_iterator","iterator over finite faces of the triangulation.");

	simple_python_iterator<Finite_edges_iterator>::declare("Edge_iterator","\n\niterator over edges");

	simple_python_iterator<All_vertices_iterator>::declare("All_vertices_iterator","\n\niterator over all vertices");
	simple_python_iterator<All_faces_iterator>::declare("All_faces_iterator","\n\niterator over all faces.");
	simple_python_iterator<All_edges_iterator>::declare("All_edges_iterator","\n\niterator over all edges");

	circulator_to_py_iterator<Face_circulator,Face_handle>::declare("Face_circulator","\n\n is an iterator over faces but without a stop iteration");
// Line_face_circulator_to_py_iterator<Line_face_circulator,Face_handle>::declare("Line_face_circulator","is an iterator over faces but without a stop iteration"); // Where is the code for this ???
	circulator_to_py_iterator<Vertex_circulator,Vertex_handle>::declare("Vertex_circulator","is an iterator over vertices but without a stop iteration");
	simple_python_circulator<Edge_circulator>::declare("Edge_circulator","is an iterator over edges but without a stop iteration");
}

void export_Triangulation_2()
{
	Py_Triangulation_2<K>();
}
